package mecproc;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Set;

import espest.EstadoAbstracto;
import espest.OperadorAbstracto;
import espest.Transicao;

public abstract class MecProcura<E extends EstadoAbstracto> implements Comparator<No<E>>
{

	protected PriorityQueue<No<E>> abertos = new PriorityQueue<No<E>>(1,this);
	protected Objectivo<E> objectivo;
	
	protected void iniciar(){
		abertos.clear();
	}
	
	protected No<E> rmvNoAbertos(){
		return abertos.poll();
	}
	
	protected void insNoAbertos(No<E> no){
		abertos.add(no);
	}
	
	public LinkedList<No<E>> procurar(E estadoInicial, Objectivo<E> objectivo, OperadorAbstracto<E>[] operadores) throws OutOfMemoryError
	{
		iniciar();
		abertos.add(new No<E>(estadoInicial));
		No<E> no;
		this.objectivo = objectivo;
		
		while (!abertos.isEmpty()){		
			no = rmvNoAbertos();
			if(objectivo.satisfeito(no.getEstado()))
				return gerarSolucao(no);
			else
				expandir(no, operadores);
		}
		return null;
	}
	
	public void expandir(No<E> no, OperadorAbstracto<E>[] operadores)
	{
		for(OperadorAbstracto<E> op: operadores){
			Set<Transicao<E>> transicoes = op.aplicar(no.getEstado());
			if(transicoes!=null){
				for(Transicao<E> tr: transicoes){
					insNoAbertos(new No<E>(tr,no));
				}
			}
		}
	}


	public LinkedList<No<E>> gerarSolucao(No<E> no){
		LinkedList<No<E>> solucao = new LinkedList<No<E>>();
		No<E> act;
		act=no;
		do{
			solucao.addFirst(act);
			act=act.getAntecessor();
		}while(act!=null);
		return solucao;
	}
}